package org.orcas.kocl.compiler.core;

import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.impl.EClassifierImpl;
import org.eclipse.ocl.OCL;
import org.eclipse.ocl.ParserException;
import org.eclipse.ocl.ecore.Constraint;
import org.eclipse.ocl.ecore.EcoreEnvironmentFactory;
import org.eclipse.ocl.expressions.OCLExpression;
import org.eclipse.ocl.helper.OCLHelper;

public class KOCLCompiler {
	
	public void test(){
		
		//_testEqualOperation();
		//_testNotEqualOperation();
		//_testOclAsTypeOperation();
		//_testOclIsKindOfOperation();
		//_testOclIsTypeOfOperation();
		//_testMinusOperation();
		//_testPlusOperation();
		//_testAbsOperation();
		//_testSizeOperation();
		//_testSequences();
		//_testLetExpression();
		//_testRound();
		//_testDiv();
		//_testCount();
		//_testCollectionOperations();
		//testIfExpression();
		_testIteratorExpression();
		
	}
	
	private void _testIteratorExpression(){
		
		final String[] strs = new String[]{
			//"Set{1,2,3}->select(a | a.mod(2) = 0)",
			//"Sequence{1,2,3,4,5}->select(a | a = 2)",
			"Set{Set{1},Set{1,2}}->select(c | c->size() > 1)",
			"Set{1,2}->select(c | c->size() > 1)",
			//"Sequence{1,2,3,4,5}->forAll(a | a > 2)",
			"OrderedSet{'marcellus', 'castro'}->select(j | j.size() < 6)"
		};
		_print(strs);
	}

	private void _testIfExpression(){
		
		final String[] strs = new String[]{
			"if 1+3 then 2+2 else 2+3 endif"
		};
		_print(strs);
	}
	
	private void _testCollectionOperations(){
		final String[] strs = new String[]{
			//"Sequence{1,2,3,1}->includes(1)",
			//"Sequence{1,2,3,1}->excludes(4)",
			//"Sequence{1,2,3,1}->includesAll(Sequence{1,2})"
			"Set{1,2,3} - Set{1,2}",
			"Set{1,2,3}->intersection(Set{1})"
		};
		_print(strs);
	}
	
	private void _testCount(){
		final String[] strs = new String[]{
			"Sequence{1,2,3,1}->count(1)"	
		};
		_print(strs);
	}
	private void _testRound(){
		final String[] strs = new String[] {
				"2.round()",
				"2.3.round()"
		};
		_print(strs);
	}
	
	private void _testDiv(){
		final String[] strs = new String[] {
				"(3+1).div(0+3)",
				"-3.div(2+3)"
		};
		_print(strs);
	}
	
	private void _testLetExpression(){
		final String[] strs = new String[] {
				"let x:String = 'marcellus' in x.size() > 3",
				"let a:Integer = 3 in a + 2 > 5"
		};
		_print(strs);
	}
	
	private void _testSequences(){
		final String[] strs = new String[] {
				"Sequence{'a','b','c'}",
				"Sequence{1,2}",
				"OrderedSet{2,5}",
				"Set{1,2}",
				// "Bag{1,2,2,4}",
		}; 
		
		_print(strs);
	}
	
	private void _testSizeOperation(){
		final String[] strs = new String[] {
				"'aaaaaaaaa'.size()",
				"Sequence{'a', 'b', 'c'}->size()",
		}; 
		
		_print(strs);
	}
	
	private void _testAbsOperation(){
		final String[] strs = new String[] {
				"-33.abs()",
				"1.4.abs()",
				"(-1).abs()",
		}; 
		
		_print(strs);
	}
	
	private void _testMinusOperation(){
		final String[] strs = new String[] {
				"-3",
				"-3.2",
				"2-1",
		}; 
		
		_print(strs);
	}
	
	private void _testPlusOperation(){
		final String[] strs = new String[] {
				"2+2",
		}; 
		
		_print(strs);
	}
	
	private void _testEqualOperation(){
		final String[] strs = new String[] {
				"1.3 = 1.5",
				"1 = 2",
				"'marcellus' = 'marcellus'",
				"true = true",
				"Sequence{1,2,3,1} = Sequence{1}"
		}; 
		
		_print(strs);
	}
	
	private void _testNotEqualOperation(){
		final String[] strs = new String[] {
				"1.3 <> 1.5",
				"'Jacques' <> 'Robin'",
				"true <> false"
		};
		
		_print(strs);
	}
	
	
	private void _testOclAsTypeOperation(){
		final String[] strs = new String[] {
				"'2'.oclAsType(Integer)",
				"'2'.oclAsType(Real)",
				"2.3.oclAsType(String) "
		};
		
		_print(strs);
	}
	
	private void _testOclIsKindOfOperation(){
		final String[] strs = new String[] {
				"'2'.oclIsKindOf(String)",
				"2.3.oclIsKindOf(Real) "
		};
		
		_print(strs);
	}
	
	private void _testOclIsTypeOfOperation(){
		final String[] strs = new String[] {
				"'2'.oclIsTypeOf(String)",
				"2.3.oclIsTypeOf(Real) "
		};
		
		_print(strs);
	}
	
	private void _print(String[] expressions){
		
		OCL<?, EClassifier, ?, ?, ?, ?, ?, ?, ?, Constraint, EClass, EObject> ocl;
		ocl = OCL.newInstance(EcoreEnvironmentFactory.INSTANCE);
		
		OCLHelper<EClassifier, ?, ?, Constraint> helper = ocl.createOCLHelper();
		helper.setContext(new EClassifierImpl() {
		});
		
		JavaVisitor javaVisitor = JavaVisitor.getEcoreVersion();

		try {
			for (String equalExpression : expressions) {
				OCLExpression<EClassifier> expression =  helper.createQuery(equalExpression);
				
				System.out.println("------------------------------");
				System.out.printf("Expression: %s\n", equalExpression);
				System.out.println(expression.accept(javaVisitor));
				System.out.println("------------------------------");
			}
		} catch (ParserException e) {
			e.printStackTrace();
		}
	}
}
